/* IR protocols example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/queue.h"
#include "sdkconfig.h"
#include "driver/rmt.h"
#include "nvs_flash.h"
#include "esp_system.h"

#include "RCS_protocol.h"
#include "RCS_slave.h"
#include "RCS_btn.h"
#include "RCS_fire.h"
#include "RCS_scr.h"
#include "RCS_ble_slave.h"
#include "RCS_led.h"
#include "RCS_nfc.h"
#include "RCS_adc.h"
#include "by8301.h"

/////////////////////GLOBAL VARIABLE/////////////////////
extern rcs_slave_system_t rcsSystem;

QueueHandle_t xUploadDataQueue; // 发射子弹后需要上报数据

TaskHandle_t txTaskHandle;
TaskHandle_t bleserverTaskHandle;
TaskHandle_t nfcTaskHandle;

/*
在led任务中，被击中事件响应结束以后把事件bit置0.
震动任务只能getbit
*/

static const char *SYS_TAG = "SHOOT_DEV";
static const char *LED_TAG = "LED_TAG";
static const char *BLE_TAG = "BLE_TAG";
static const char *SCR_TAG = "SCR_TAG";
static const char *NFC_TAG = "NFC_TAG";
static const char *FIRE_TAG = "FIRE_TAG";

/////////////////////TASK DECLAIRATION/////////////////////
static void ir_tx_task(void *arg);

static void ble_shoot_server_task(void *arg);

static void led_task(void *arg);

static void scr_task(void *arg);

static void nfc_task(void *arg);

static void battery_monitor_task(void *arg);

static void main_task(void *arg)
{
    game_event_init();
    by8301_init();
    // 电量查询初始化
    rcs_adc1_init();
    rcsSystem.device.battery = rcs_adc_battery_read();

    // 创建红外消息队列，在红外接收任务中把信息放入队列，在蓝牙任务里从队列里获取信息，发送给ble server
    xUploadDataQueue = xQueueCreate(10, GUN_POI_UPL_PACK_MAX_LEN);

    // 灯光任务：
    xTaskCreate(led_task, "led_task", 1024 * 3, NULL, 5, NULL);

    // 供电
    power_init();

    vTaskDelay(pdMS_TO_TICKS(1000));

    ESP_LOGE(SYS_TAG, "..........power_init............");

    if (scr_init() == ESP_OK)
    {
        // ESP_LOGE(SYS_TAG, "..........HAS SCREEN............");
        // 屏幕任务:
        xTaskCreate(scr_task, "scr_task", 1024 * 100, NULL, 8, NULL);
    }
    else
    {
        // ESP_LOGE(SYS_TAG, "..........NO SCREEN............");
        rcsSystem.device.is_hold_scr = false;
        rcsSystem.device.device_class = GUN_POINT;
    }

    // 蓝牙任务:
    xTaskCreate(ble_shoot_server_task, "ble_shoot_server_task", 1024 * 25, NULL, 10, &bleserverTaskHandle);

    xTaskCreate(battery_monitor_task, "battery_monitor_task", 1024 * 5, NULL, 6, NULL);

    // 红外发射任务:
    xTaskCreate(ir_tx_task, "ir_tx_task", 1024 * 10, NULL, 12, &txTaskHandle);

    // nfc任务
    xTaskCreate(nfc_task, "nfc_task", 1024 * 5, NULL, 9, &nfcTaskHandle);

    ESP_LOGI(SYS_TAG, "[APP] Startup..");
    ESP_LOGI(SYS_TAG, "[APP] IDF version: %s", esp_get_idf_version());
    ESP_LOGI(SYS_TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());

    // 按钮初始化
    btn_init();
    vTaskDelay(pdMS_TO_TICKS(20000));
    vTaskDelete(NULL);
    return;
}

void app_main(void)
{
    /* Initialize NVS. */
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
    xTaskCreate(main_task, "main_task", 1024 * 20, NULL, 5, NULL);
}

/**
 * @brief RMT Transmit Task
 *
 */

#define MS_INTERVAL(x) (x / TIME_BASE - 1)
#define TIME_BASE 125

static void ir_tx_task(void *arg)
{
    bool pulling = false;
    bool suspend_flag = false;
    bool bullets_changed = false;
    uint16_t fire_count = 0;
    uint16_t reloading_count = 0;
    rcs_rmt_tx_init();
    player_t zero_player = {
        .id = 0,
        .damage = 0,
        .team = 0,
        .room = 0,
    };

    while (1)
    {
        if (rcsSystem.device.is_connect_master == CONNECTED_BLE)
        {
            // 如果游戏没开始或者死亡，挂起。
            if (!rcsSystem.game.start || !rcsSystem.game.player.living)
            {
                bullets_changed = false;
                fire_count = 0;
                ESP_LOGI(BLE_TAG, "game.start:%d, player.living:%d.Suspend ir_tx_task",
                         rcsSystem.game.start, rcsSystem.game.player.living);
                vTaskSuspend(NULL);
            }
            if (is_pulling_trigger())
            {
                bullet_data_set(false,&(rcsSystem.game.player));
                if (rcsSystem.game.player.bullet_nums > 0 && fire(false))
                {
                    bullets_changed = true;
                    change_player_bullet_nums(rcsSystem.game.player.bullet_nums - 1);
                }
            }
            // 1s判断一次要不要发送报文。有可能子弹在1s之内打空了，所以还是要在这里检测
            fire_count++;
            if (fire_count > MS_INTERVAL(1000))
            {
                if (bullets_changed)
                {
                    fire_success_handle();
                }
                // 清空累计值。
                bullets_changed = false;
                fire_count = 0;
            }
            vTaskDelay(pdMS_TO_TICKS(TIME_BASE));
        }
        else
        {
            // 发射空子弹。
            if (is_pulling_trigger())
            {
                bullet_data_set(false, &zero_player);
                fire(false);
            }
            vTaskDelay(pdMS_TO_TICKS(TIME_BASE));
        }
    }
    vTaskDelete(NULL);
}

static void ble_shoot_server_task(void *arg)
{
    rcs_ble_init();
    ESP_LOGI(BLE_TAG, "ble_shoot_server_task Startup..");

    rcs_start_advertise(rcsSystem.device.wait_new_master);
    // package
    uint8_t package[GUN_POI_UPL_PACK_MAX_LEN];
    BaseType_t xStatus;
    while (1)
    {
        switch (rcsSystem.device.is_connect_master)
        {
        case DISCONNECT_BLE:
        {
            ESP_LOGI(BLE_TAG, "didn't connect, so Suspend ble_shoot_server_task ..");
            // 没连接上主机时，挂起自己，ble的fsm还能工作，等待连上server以后再恢复此任务
            rcs_stop_advertise();
            rcs_start_advertise(rcsSystem.device.wait_new_master);
            vTaskSuspend(NULL);
        }
        case INITING_BLE:
        {
            uint8_t pack_len = 0;
            uint8_t *package = make_verify_package(&pack_len);
            ESP_LOGE(BLE_TAG, "send VERTIFY package to MASTER");
            rcs_notify_client(package, pack_len);
            free(package);
            vTaskDelay(pdMS_TO_TICKS(1000));
            break;
        }
        case CONNECTED_BLE:
        {
            // 只要连接上了ble server,就把队列里的消息读取并发送，如果没连上也读取会浪费掉消息。
            xStatus = xQueueReceive(xUploadDataQueue, package, pdMS_TO_TICKS(500));
            if (xStatus == pdPASS)
            {
                uint16_t pack_len = package[2];
                rcs_notify_client(package, pack_len);
            }
            break;
        }
        default:
            break;
        }
    }
}

#define EVENT_INTERVAL 100
#define ADVERTISING_INTERVAL 100

static void scr_task(void *arg)
{
    ESP_LOGE(SCR_TAG, "ssd1306_show_task start");
    rcsSystem.device.is_hold_scr = true;
    rcsSystem.device.device_class = GUN_SCREEN;
    uint16_t time_count = 0;
    uint8_t scr_page = SCR_START_PAGE;
    rcsSystem.game.player.living = false;
    bool in_start = true;
    while (in_start)
    {
        time_count++;
        in_start = start_page_ui(&time_count, &scr_page);
        vTaskDelay(pdMS_TO_TICKS(FRESH_BASE));
    }
    while (1)
    {
        time_count++;
        goto_new_page(&scr_page);
        switch (scr_page)
        {
        case SCR_DISCONNET_PAGE:
        {
            disconnect_page_ui(&time_count, &scr_page);
            break;
        }
        case SCR_WAITING_PAGE:
        {
            wait_game_start_page_ui(&time_count, &scr_page);
            break;
        }
        case SCR_LIVING_PAGE:
        {
            game_living_page_ui(&time_count, &scr_page);
            break;
        }
        default:

            break;
        }
        vTaskDelay(pdMS_TO_TICKS(FRESH_BASE));
    }
    vTaskDelete(NULL);
}

static void nfc_task(void *arg)
{
    if (nfc_init() != ESP_OK)
    {
        ESP_LOGE(NFC_TAG, "nfc_init() != ESP_OK,vTaskDelete");
        rcsSystem.device.is_hold_nfc = false;
        vTaskDelete(NULL);
    }
    rcsSystem.device.is_hold_nfc = true;
    ESP_LOGI(NFC_TAG, "nfc_task Startup..");
    while (1)
    {
        if (rcsSystem.device.is_connect_master == CONNECTED_BLE)
        {
            open_rc522();
            detect_tag();
            // test_add_increase_damage_tag();
            // test_add_increase_hp_tag();
            // test_add_reborn_tag();
            // test_add_increase_bulletnum_tag();
            close_rc522();
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
        else
        {
            ESP_LOGI(BLE_TAG, "didn't connect, so Suspend nfc_task ..");
            vTaskSuspend(NULL);
        }
    }
}

static void led_task(void *arg)
{
    rcs_event_t game_event = NO_EVENT;
    rcs_event_t last_game_event = NO_EVENT;
    uint8_t event_count = 0;
    uint8_t game_no_start_count = 0;
    uint8_t advertising_count = 0;
    uint8_t no_connect_count = 0;
    uint8_t low_battery_count = 0;
    led_t led = {
        .state = true,
        .delay_time = 1000};
    led_init();
    ESP_LOGI(LED_TAG, "led_task Startup..");
    while (1)
    {
        // 先判断有没有事件，如果有先执行事件的显示，没有事件再根据状态显示，只会有一种事件
        last_game_event = game_event;
        get_game_event_state(&game_event);
        if (game_event)
        {
            // 选择事件多久清0
            if (last_game_event != game_event)
            {
                ESP_LOGI(LED_TAG, "game event: %s", event_name(game_event));
                switch (game_event)
                {
                case REMOTE_COMM_EVENT:
                {
                    event_count = 4;
                    break;
                }
                case HIT_SUCCESS:
                {
                    event_count = 2;
                    break;
                }
                default:
                    break;
                }
            }
            if (event_count % 2 == 0)
            {
                led.state = true;
            }
            else
            {
                led.state = false;
            }
            led.delay_time = EVENT_INTERVAL;
            event_count--;
            if (event_count == 0)
            {
                // 灯光任务再执行完事件以后会把事件清空。
                set_game_event(NO_EVENT);
            }
        }
        else
        {
            if (rcsSystem.device.is_connect_master == CONNECTED_BLE)
            {
                if (rcsSystem.game.start)
                {
                    // 游戏开始
                    if (rcsSystem.game.player.living)
                    {
                        // 活着
                        led.state = (rcsSystem.game.player.team % 2 == 1) ? true : false;
                    }
                    else
                    {
                        // 死亡
                        led.state = !led.state;
                        led.delay_time = 500;
                    }
                }
                else
                {
                    // 游戏未开始
                    if (rcsSystem.device.low_batt)
                    {
                        // 低电量警告
                        if (low_battery_count >= 50)
                        {
                            low_battery_count = 0;
                        }
                        if (low_battery_count < 2)
                        {
                            led.state = true;
                        }
                        else
                        {
                            led.state = false;
                        }
                        led.delay_time = 100;
                        low_battery_count++;
                    }
                    else
                    {
                        // 普通情况
                        if (game_no_start_count >= 20)
                        {
                            game_no_start_count = 0;
                        }
                        led.state = (game_no_start_count < 10) ? true : false;
                        led.delay_time = 100;
                        game_no_start_count++;
                    }
                }
            }
            else
            {
                // 没连接服务器
                if (rcsSystem.device.wait_new_master)
                {
                    // 广播中
                    led.state = (advertising_count % 2 == 0) ? true : false;
                    led.delay_time = ADVERTISING_INTERVAL;
                    advertising_count++;
                }
                else
                {
                    if (no_connect_count >= 40)
                    {
                        no_connect_count = 0;
                    }
                    led.state = (no_connect_count < 10) ? true : false;
                    led.delay_time = 100;
                    no_connect_count++;
                }
            }
        }
        set_led_val(led.state);
        vTaskDelay(pdMS_TO_TICKS(led.delay_time));
    }
}

static void battery_monitor_task(void *arg)
{
    while (1)
    {
        vTaskDelay(pdMS_TO_TICKS(10000));
        rcsSystem.device.battery = rcs_adc_battery_read();
        if (rcsSystem.device.battery < LOW_BATTERY_THRESHOLD)
        {
            rcsSystem.device.low_batt = true;
        }
        else
        {
            rcsSystem.device.low_batt = false;
        }

        if (rcsSystem.device.is_connect_master != DISCONNECT_BLE)
        {
            uint8_t pack_len = 0;
            uint8_t *package = make_battery_package(&pack_len);
            ESP_LOGE(BLE_TAG, "send battery package to MASTER");
            esp_err_t ret = rcs_notify_client(package, pack_len);
            free(package);
        }
        }
}